'''
Created on Feb 25, 2012

@author: daoxuandung
'''

import webapp2
from webapp2_extras import auth
from webapp2_extras import sessions
from uuid import uuid4
from entity.fb_entity import *
import urllib
import util
import logging
import json

        
def user_required(handler):
    """
    Decorator for checking if there's a user associated with the current session.
    Will redirect to login page for normal HTTP Request
    For AJAX request, it only returns the 401 - Unauthorized status code
    """
    def check_login(self, *args, **kwargs):
        if not util.get_current_user_key():
            # If handler has no login_url specified invoke a 401 error
            try:
                if util.is_ajax(self.request) is False:
                    login_url = webapp2.uri_for('login')
                    login_url +=  "?redirect-url=" + urllib.quote(self.request.path_qs)
                    self.redirect(login_url, abort=True)
                else: 
                    self.abort(401)
            except (AttributeError, KeyError):
                self.abort(401)
        else:
            return handler(self, *args, **kwargs)

    return check_login


def user_data_print(handler):
    """
    Decorator for printing out some user information of the current session 
    For facebook user print out friendlist data including name + id
    """
    def check_user(self, *args, **kwargs):
        try:
            # check if user exist, and print user data by passing template value 
            user_key = util.get_current_user_key()
            if (user_key is not None and user_key.get() is not None):
                # pass user data to self 
                user = user_key.get()
                user_data = util.ndb_to_dict(user) 
                self.user_data = json.dumps(user_data);
                
                # if user has facebook id, retrieve friend list
                if (user.fb_id is not None):
                    qry = FacebookUser.query( FacebookUser.fb_id == user.fb_id)
                    fb_user = qry.fetch(limit=1)
                    if fb_user is not None and len(fb_user) > 0:
                        fb_user = fb_user[0]
                        self.user_friends = fb_user.friend_list
        except:
            # just skip importing if error happens
            logging.warn("Cannot import user data or user friends' data")
                
        return handler(self, *args, **kwargs)
    
    return check_user
        
 
class BaseHandler(webapp2.RequestHandler):
    """
    BaseHandler for all requests
    Holds the auth and session properties so they are reachable for all requests
     """

    def dispatch(self):
        """
        Save the sessions for preservation across requests
        """
        try:
            self.csrf_protect = False
            self.init_csrf()
            super(BaseHandler, self).dispatch()
        finally:
            self.session_store.save_sessions(self.response)
    
    # CSRF protection        
    def init_csrf(self):
        """
        Issue and handle CSRF token as necessary
        """
        self.csrf_token = self.request.cookies.get('csrf')
        if not self.csrf_token:
            self.csrf_token = str(uuid4())[:8]
            self.response.set_cookie('csrf', self.csrf_token, httponly=True)
        
        if self.request.method == 'POST' and self.csrf_protect \
            and self.csrf_token != self.request.get('_csrf_token'):
            self.abort(403)


    # Authentication
    @webapp2.cached_property
    def auth(self):
        return auth.get_auth()

    @webapp2.cached_property
    def session_store(self):
        return sessions.get_store(request=self.request)

    @webapp2.cached_property
    def auth_config(self):
        """
              Dict to hold urls for login/logout
          """
        return {
            'login_url': self.uri_for('login'),
            'logout_url': self.uri_for('logout')
        }
        
    def login(self, user, remember=False):
        """
        user should be webapp2_extras.appengine.auth.models.User
        """
        user_dict = self.auth.store.user_to_dict(user)
        self.auth.set_session(user_dict, remember=remember)